#include "PPMCTest.h"
#include "../Contexto.h"
#include <iostream>

using namespace std;

void actualizarSimboloEnCadaModeloHastaEncontrarlo(const Simbolo simbolo,
	Contexto::ListadoModelos &listadoModelos)
{
	Contexto::ListadoModelos::reverse_iterator ritModelo;
	bool encontrado=false;

	for (ritModelo=listadoModelos.rbegin();
		ritModelo!=listadoModelos.rend() && (not encontrado);
		ritModelo++)
	{
		encontrado=(*ritModelo)->contiene(simbolo);
		(*ritModelo)->actualizarFrecuencia(simbolo);
	}
}

int contextoTest()
{
	cout << endl;
	cout << "===============================" << endl;
	cout << "P R U E B A S   C O N T E X T O" << endl;
	cout << "===============================" << endl;
	cout << endl;

	Contexto contexto(3);

	Contexto::ListadoModelos &lm=contexto.getModelos();

	cout << "Luego de crear el contexto el listado devuelto por getModelos " <<
		"es de tamaño 1: " << (lm.size()==1) << endl;

	// A
	actualizarSimboloEnCadaModeloHastaEncontrarlo('A',lm);
	contexto.addSimbolo('A');
	lm=contexto.getModelos();
	cout << "Luego de agregar la A en todos los modelos devueltos y en el " <<
		"contexto el listado devuelto por getModelos es de tamaño 2: " <<
		(lm.size()==2) << endl;

	actualizarSimboloEnCadaModeloHastaEncontrarlo('B',lm);
	contexto.addSimbolo('B');
	lm=contexto.getModelos();
	cout << "Luego de agregar la B en todos los modelos devueltos y en el " <<
		"contexto el listado devuelto por getModelos es de tamaño 3: " <<
		(lm.size()==3) << endl;

	actualizarSimboloEnCadaModeloHastaEncontrarlo('C',lm);
	contexto.addSimbolo('C');
	lm=contexto.getModelos();
	cout << "Luego de agregar la C en todos los modelos devueltos y en el " <<
		"contexto el listado devuelto por getModelos es de tamaño 4: " <<
		(lm.size()==4) << endl;

	actualizarSimboloEnCadaModeloHastaEncontrarlo('D',lm);
	contexto.addSimbolo('D');
	lm=contexto.getModelos();
	cout << "Luego de agregar la D en todos los modelos devueltos y en el " <<
		"contexto el listado devuelto por getModelos es de tamaño 4: " <<
		(lm.size()==4) << endl;
	// orden 0
	Modelo *m=*(lm.begin());
	cout << "Modelo cero contiene ESC con frecuencia 4: " <<
		(m->getFrecuenciaSimbolo(SimboloESC)==4) << endl;
	cout << "Modelo cero contiene A con frecuencia 1: " <<
		(m->getFrecuenciaSimbolo('A')==1) << endl;
	cout << "Modelo cero contiene B con frecuencia 1: " <<
		(m->getFrecuenciaSimbolo('B')==1) << endl;
	cout << "Modelo cero contiene C con frecuencia 1: " <<
		(m->getFrecuenciaSimbolo('C')==1) << endl;
	cout << "Modelo cero contiene D con frecuencia 1: " <<
		(m->getFrecuenciaSimbolo('D')==1) << endl;
	// orden 1
	Modelo *mA=m->getModeloSiguienteOrden('A');
	cout << "Modelo A contiene ESC con frecuencia 1: " <<
		(mA->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo A contiene B con frecuencia 1: " <<
		(mA->getFrecuenciaSimbolo('B')==1) << endl;
	Modelo *mB=m->getModeloSiguienteOrden('B');
	cout << "Modelo B contiene ESC con frecuencia 1: " <<
		(mB->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo B contiene C con frecuencia 1: " <<
		(mB->getFrecuenciaSimbolo('C')==1) << endl;
	Modelo *mC=m->getModeloSiguienteOrden('C');
	cout << "Modelo C contiene ESC con frecuencia 1: " <<
		(mC->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo C contiene D con frecuencia 1: " <<
		(mC->getFrecuenciaSimbolo('D')==1) << endl;
	Modelo *mD=m->getModeloSiguienteOrden('D');
	cout << "Modelo D contiene ESC con frecuencia 1: " <<
		(mD->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo D solo contiene 1 simbolo: " <<
		(mD->getFrecuenciasSimbolos().size()==1) << endl;
	// orden 2
	Modelo *mAB=m->getModeloSiguienteOrden('A')
		->getModeloSiguienteOrden('B');
	cout << "Modelo AB contiene ESC con frecuencia 1: " <<
		(mAB->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo AB contiene C con frecuencia 1: " <<
		(mAB->getFrecuenciaSimbolo('C')==1) << endl;
	Modelo *mBC=m->getModeloSiguienteOrden('B')
		->getModeloSiguienteOrden('C');
	cout << "Modelo BC contiene ESC con frecuencia 1: " <<
		(mBC->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo BC contiene D con frecuencia 1: " <<
		(mBC->getFrecuenciaSimbolo('D')==1) << endl;
	Modelo *mCD=m->getModeloSiguienteOrden('C')
		->getModeloSiguienteOrden('D');
	cout << "Modelo CD contiene ESC con frecuencia 1: " <<
		(mCD->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo CD solo contiene 1 simbolo: " <<
		(mCD->getFrecuenciasSimbolos().size()==1) << endl;
	// orden 3
	Modelo *mABC=m->getModeloSiguienteOrden('A')
		->getModeloSiguienteOrden('B')
		->getModeloSiguienteOrden('C');
	cout << "Modelo ABC contiene ESC con frecuencia 1: " <<
		(mABC->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo ABC contiene D con frecuencia 1: " <<
		(mABC->getFrecuenciaSimbolo('D')==1) << endl;
	Modelo *mBCD=m->getModeloSiguienteOrden('B')
		->getModeloSiguienteOrden('C')
		->getModeloSiguienteOrden('D');
	cout << "Modelo BCD contiene ESC con frecuencia 1: " <<
		(mBCD->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo BCD solo contiene 1 simbolo: " <<
		(mBCD->getFrecuenciasSimbolos().size()==1) << endl;

	actualizarSimboloEnCadaModeloHastaEncontrarlo('A',lm);
	contexto.addSimbolo('A');
	lm=contexto.getModelos();
	m=*lm.begin();
	cout << "Luego de agregar una A el modelo 0 contiene ESC con frecuencia 4: " <<
		(m->getFrecuenciaSimbolo(SimboloESC)==4) << endl;
	cout << "Contiene A con frecuencia 2: " <<
		(m->getFrecuenciaSimbolo('A')==2) << endl;
	cout << "El modelo D Contiene A con frecuencia 1: " <<
		(m->getModeloSiguienteOrden('D')->getFrecuenciaSimbolo('A')==1) << endl;
	cout << "El modelo CD Contiene A con frecuencia 1: " <<
		(m->getModeloSiguienteOrden('C')
		->getModeloSiguienteOrden('D')->getFrecuenciaSimbolo('A')==1) << endl;
	cout << "El modelo BCD Contiene A con frecuencia 1: " <<
		(m->getModeloSiguienteOrden('B')->getModeloSiguienteOrden('C')
		->getModeloSiguienteOrden('D')->getFrecuenciaSimbolo('A')==1) << endl;

	actualizarSimboloEnCadaModeloHastaEncontrarlo('B',lm);
	contexto.addSimbolo('B');
	lm=contexto.getModelos();
	m=*lm.begin();
	cout << "Luego de agregar una B el modelo 0 contiene ESC con frecuencia 4: " <<
		(m->getFrecuenciaSimbolo(SimboloESC)==4) << endl;
	cout << "Contiene B con frecuencia 1: " <<
		(m->getFrecuenciaSimbolo('B')==1) << endl;
	cout << "El modelo A Contiene B con frecuencia 2: " <<
		(m->getModeloSiguienteOrden('A')->getFrecuenciaSimbolo('B')==2) << endl;
	cout << "El modelo DA Contiene B con frecuencia 1: " <<
		(m->getModeloSiguienteOrden('D')
		->getModeloSiguienteOrden('A')->getFrecuenciaSimbolo('B')==1) << endl;
	cout << "El modelo CDA Contiene B con frecuencia 1: " <<
		(m->getModeloSiguienteOrden('C')->getModeloSiguienteOrden('D')
		->getModeloSiguienteOrden('A')->getFrecuenciaSimbolo('B')==1) << endl;


	actualizarSimboloEnCadaModeloHastaEncontrarlo('C',lm);
	contexto.addSimbolo('C');
	contexto.getModelos();
	actualizarSimboloEnCadaModeloHastaEncontrarlo('D',lm);
	contexto.addSimbolo('D');
	lm=contexto.getModelos();

	lm=contexto.getModelos();
	cout << "Luego de agregar CD nuevamente al contexto y haber actualizado las " <<
		"frecuencias el listado devuelto por getModelos es de tamaño 4: " <<
		(lm.size()==4) << endl;

	m=*(lm.begin());
	cout << "Modelo cero contiene ESC con frecuencia 4: " <<
		(m->getFrecuenciaSimbolo(SimboloESC)==4) << endl;
	cout << "Modelo cero contiene A con frecuencia 2: " <<
		(m->getFrecuenciaSimbolo('A')==2) << endl;
	cout << "Modelo cero contiene B con frecuencia 1: " <<
		(m->getFrecuenciaSimbolo('B')==1) << endl;
	cout << "Modelo cero contiene C con frecuencia 1: " <<
		(m->getFrecuenciaSimbolo('C')==1) << endl;
	cout << "Modelo cero contiene D con frecuencia 1: " <<
		(m->getFrecuenciaSimbolo('D')==1) << endl;
	// orden 1
	mA=m->getModeloSiguienteOrden('A');
	cout << "Modelo A contiene ESC con frecuencia 1: " <<
		(mA->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo A contiene B con frecuencia 2: " <<
		(mA->getFrecuenciaSimbolo('B')==2) << endl;
	mB=m->getModeloSiguienteOrden('B');
	cout << "Modelo B contiene ESC con frecuencia 1: " <<
		(mB->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo B contiene C con frecuencia 1: " <<
		(mB->getFrecuenciaSimbolo('C')==1) << endl;
	mC=m->getModeloSiguienteOrden('C');
	cout << "Modelo C contiene ESC con frecuencia 1: " <<
		(mC->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo C contiene D con frecuencia 1: " <<
		(mC->getFrecuenciaSimbolo('D')==1) << endl;
	mD=m->getModeloSiguienteOrden('D');
	cout << "Modelo D contiene ESC con frecuencia 1: " <<
		(mD->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo D contiene A con frecuencia 1: " <<
		(mD->getFrecuenciaSimbolo('A')==1) << endl;
	// orden 2
	mAB=m->getModeloSiguienteOrden('A')
		->getModeloSiguienteOrden('B');
	cout << "Modelo AB contiene ESC con frecuencia 1: " <<
		(mAB->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo AB contiene C con frecuencia 2: " <<
		(mAB->getFrecuenciaSimbolo('C')==2) << endl;
	mBC=m->getModeloSiguienteOrden('B')
		->getModeloSiguienteOrden('C');
	cout << "Modelo BC contiene ESC con frecuencia 1: " <<
		(mBC->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo BC contiene D con frecuencia 1: " <<
		(mBC->getFrecuenciaSimbolo('D')==1) << endl;
	mCD=m->getModeloSiguienteOrden('C')
		->getModeloSiguienteOrden('D');
	cout << "Modelo CD contiene ESC con frecuencia 1: " <<
		(mCD->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo CD contiene A con frecuencia 1: " <<
		(mCD->getFrecuenciaSimbolo('A')==1) << endl;
	Modelo *mDA=m->getModeloSiguienteOrden('D')
		->getModeloSiguienteOrden('A');
	cout << "Modelo DA contiene ESC con frecuencia 1: " <<
		(mDA->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo DA contiene B con frecuencia 1: " <<
		(mDA->getFrecuenciaSimbolo('B')==1) << endl;
	// orden 3
	mABC=m->getModeloSiguienteOrden('A')
		->getModeloSiguienteOrden('B')
		->getModeloSiguienteOrden('C');
	cout << "Modelo ABC contiene ESC con frecuencia 1: " <<
		(mABC->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo ABC contiene D con frecuencia 2: " <<
		(mABC->getFrecuenciaSimbolo('D')==2) << endl;
	mBCD=m->getModeloSiguienteOrden('B')
		->getModeloSiguienteOrden('C')
		->getModeloSiguienteOrden('D');
	cout << "Modelo BCD contiene ESC con frecuencia 1: " <<
		(mBCD->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo BCD contiene A con frecuencia 1: " <<
		(mBCD->getFrecuenciaSimbolo('A')==1) << endl;
	Modelo *mCDA=m->getModeloSiguienteOrden('C')
		->getModeloSiguienteOrden('D')
		->getModeloSiguienteOrden('A');
	cout << "Modelo CDA contiene ESC con frecuencia 1: " <<
		(mCDA->getFrecuenciaSimbolo(SimboloESC)==1) << endl;
	cout << "Modelo CDA contiene B con frecuencia 1: " <<
		(mCDA->getFrecuenciaSimbolo('B')==1) << endl;

	lm=contexto.getModelos();
	m=contexto.getModeloMayorOrden();
	Contexto::ListadoModelos::reverse_iterator itlm=lm.rbegin();

	while (itlm!=lm.rend())
	{
		cout << "Coincide el modelo del listado obtenido con getModelos recorrido "
			<< "en reversa con el modelo hecho con el recorrido getModeloMayorOrden"
			<< " y getModeloAnteriorOrden: " << (m==(*itlm)) << endl;
		m=contexto.getModeloAnteriorOrden();
		itlm++;
	}
	cout << "Al terminar de recorrer el listado la última devolución " <<
		"hecha por getModeloAnteriorOrden es NULL: " << (m==NULL) << endl;

	lm=contexto.getModelos();
	m=contexto.getModeloMayorOrden();
	itlm=lm.rbegin();

	while (itlm!=lm.rend())
	{
		cout << "Coincide el modelo del listado obtenido con getModelos recorrido "
			<< "en reversa con el modelo hecho con el recorrido getModeloMayorOrden"
			<< " y getModeloAnteriorOrden por segunda vez: " << (m==(*itlm)) << endl;
		m=contexto.getModeloAnteriorOrden();
		itlm++;
	}
	cout << "Al terminar de recorrer el listado la última devolución " <<
		"hecha por getModeloAnteriorOrden es NULL por segunda vez: " <<
		(m==NULL) << endl;

	return 0;
}
